import { RepoLink, Link } from 'libframe-docs/components'

> We recommend taking the <Link text="React Tour" href="/react-tour" /> or <Link text="Vue Tour" href="/vue-tour" /> before reading this guide.
> The tour explains what the `_default.page.*` files are about.

## `onBeforeRender()`

The usual way to fetch data is to use a `onBeforeRender()` hook.

```js
// /pages/movies.page.server.js
// Environment: Node.js

import fetch from "node-fetch";

export { onBeforeRender }

async function onBeforeRender(pageContext) {
  // `.page.server.js` files always run in Node.js; we could use SQL/ORM queries here.
  const response = await fetch("https://movies.example.org/api")
  let movies = await response.json()

  // `movies` will be serialized and passed to the browser; we select only the data we
  // need in order to minimize what is sent to the browser.
  movies = movies.map(({ title, release_date }) => ({title, release_date}))

  // We make `movies` available as `pageContext.pageProps.movies`
  const pageProps = { movies }
  return {
    pageContext: {
      pageProps
    }
  }
}
```
```js
// _default.page.server.js
// Environment: Node.js

import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr'
import { renderToHtml, createElement } from 'some-ui-framework'

// We tell `vite-plugin-ssr` to make `pageContext.pageProps` available in the browser.
export const passToClient = ['pageProps']

export { render }

async function render(pageContext) {
  const { Page, pageProps } = pageContext
  const pageHtml = await renderToHtml(
    // We pass `pageProps` to `Page`
    createElement(Page, pageProps)
  )
  /* JSX:
  const pageHtml = await renderToHtml(<Page {...pageProps} />)
  */

  return escapeInject`<html>
    <div id='view-root'>
      ${dangerouslySkipEscape(pageHtml)}
    </div>
  </html>`
}
```
```js
// _default.page.client.js
// Environment: Browser

import { getPage } from 'vite-plugin-ssr/client'
import { hydrateToDom, createElement } from 'some-ui-framework'

hydrate()

async function hydrate() {
  const pageContext = await getPage()
  // `Page` is also available in the browser
  const { Page } = pageContext
  // Thanks to `passToClient = ['pageProps']` our `pageContext.pageProps` is
  // available here in the browser.
  const { Page, pageProps } = pageContext
  await hydrateToDom(
    // We pass `pageProps` to `Page`
    createElement(Page, pageProps),
    document.getElementById('view-root')
  )
  /* JSX:
  await hydrateToDom(<Page {...pageProps} />, document.getElementById('view-root'))
  */
}
```
```js
// /pages/movies.page.js
// Environment: Browser, Node.js

export { Page }

// In the `render()` and `hydrate()` functions above, we pass `pageContext.pageProps` to `Page`
function Page(pageProps) {
  const { movies } = pageProps
  // ...
}
```

Note that `vite-plugin-ssr` doesn't know anything about `pageProps`: it's an object we create to
conveniently hold all props of the `Page`.

## Global Logic

If we use the same data fetching logic for all/several pages we can factor out the common code.

```js
// user.page.server.js
import { fetchData } from './fetchData'
export const onBeforeRender = pageContext => fetchData(pageContext, 'user')
```

```js
// product.page.server.js
import { fetchData } from './fetchData'
export const onBeforeRender = pageContext => fetchData(pageContext, 'product')
```

** `onBeforeRender()` in `_default.page.server.js`**

Alternatively, we can define our global logic in `_default.page.server.js`.

```js
// /renderer/_default.page.server.js

import { fetchData } from './fetchData'

export const onBeforeRender = pageContext => {
  const page = (
    pageContext.url.startsWith('/user') && 'user' ||
    pageContext.url.startsWith('/product') && 'product'
  )
  return fetchData(pageContext, page)
}
```

**Multiple `renderer/`**

If the logic differs substantially, we may want to create <Link text={<>mutliple <code>renderer/</code> directories</>} href="/multiple-renderer" />.

** `onBeforeRender()` in `.page.server.js` and `_default.page.server.js`.**

We can also define a `onBeforeRender()` hook in the page's `.page.server.js` file,
while also defining a `onBeforeRender()` hook in `_default.page.server.js`.
See <Link href="/onBeforeRender-multiple" />.

**`onInit()`**

There is work-in-progress to implement a new `onInit()` hook to initialize global data, see [#164](https://github.com/brillout/vite-plugin-ssr/issues/164).

## Client Routing

The `.page.server.js` files are loaded only in Node.js;
our data fetching code is always exectued in Node.js.
This is convenient as it makes writing data fetching code easier.

That said, if we use [Client Routing](/useClientRouter),
then we the option to define [`onBeforeRender()` in `.page.js`](/onBeforeRender-isomorphic) instead of `.page.server.js`. In that case, `onBeforeRender()` is not only called in Node.js but also in the browser (upon page navigation).

In general, [we recommend defining `onBeforeRender()` in `.page.server.js`](/onBeforeRender-isomorphic#recommendation) (even when using Client Routing) but,
if we want to minimize requests made to our Node.js server,
then we may want to define `onBeforeRender()` in `.page.js` instead.

## Stateful Component

Alternatively, we can fetch data by using a stateful component.

> The fetched data is then not rendered to HTML, which may defeat the reason we use SSR in the first place.

We usually need to make [`pageContext.routeParams`](/pageContext) available to our stateful data-fetching component:
1. We make `pageContext.routeParams` available in the browser by adding it to [`passToClient`](/passToClient).
2. We [make `pageContext.routeParams` accessible from all our components](/pageContext-anywhere).

## GraphQL

When using GraphQL, we define GraphQL queries/fragments on a component-level, while we fetch the GraphQL data in `onBeforeRender()`.

In general, with `vite-plugin-ssr`, we have full control over rendering which means that integrating GraphQL is mostly only a matter of following the official SSR guide of the tool we want to use.

See:
 - <Link href="/apollo-graphql" />
 - <Link href="/urql" />
 - <Link href="/relay" />

## Store (Vuex/Redux...)

When using a global store ([Vuex](https://vuex.vuejs.org/), [Redux](https://redux.js.org/), [PullState](https://lostpebble.github.io/pullstate/), ...), our components don't access the fetched data directly. Instead, our components only access the store, while the fetched data merely determines the initial state of the store.

In general, with `vite-plugin-ssr`, we have full control over rendering which means that integrating a global store is mostly only a matter of following the official SSR guide of the tool we want to use.

See:
 - <Link href="/redux" />
 - <Link href="/vuex" />
 - <Link href="/pullstate" />

